#pragma once
#include <iostream>
#include <memory>
#include "Socket.hpp"
#include "Channel.hpp"
#include "Buffer.hpp"
#include "Any.hpp"
#include "EventLoop.hpp"

enum ConnStatus
{
    DISCONNECTED, // 连接关闭状态
    CONNECTING,   // 连接建立完成-待处理状态
    CONNECTED,    // 连接建立完成-各种设置完成-可以通信状态
    DISCONNECTING // 连接待关闭状态
};

class Connection;
using PtrConnection = std::shared_ptr<Connection>;
class Connection : public std::enable_shared_from_this<Connection>
{
private:
    uint64_t _conn_id; // 连接的唯一ID，便于对连接的查找
    // uint64_t _timer_id;         // 定时器ID，必须是唯一的，这块简化一下，和conn_id用一个ID
    ConnStatus _status;            // 连接的状态
    bool _enable_inactive_release; // 判断连接是否启动了非活跃连接销毁，默认为false
    EventLoop *_loop;              // 连接关联的一个EventLoop
    int _sockfd;                   // 连接关联的文件描述符
    Sock _socket;                  // 套接字的操作管理
    Channel _channel;              // 连接的事件管理
    // 缓冲区的管理
    Buffer _in_buffer;  // 输入缓冲区 -- 从Sock中读取要接收的数据
    Buffer _out_buffer; // 输出缓冲区 -- 向Sock中写入要发送的数据
    Any _context;       // 请求的接收处理上下文

    // 阶段性回调函数-提供给外界使用
    // 这四个回调函数，是让组件使用者来设置的使用的
    using ConnectionCallback = std::function<void(const PtrConnection &)>;
    using MessageCallback = std::function<void(const PtrConnection &, Buffer *)>;
    using CloseCallback = std::function<void(const PtrConnection &)>;
    using AnyEventCallback = std::function<void(const PtrConnection &)>;
    ConnectionCallback _connection_callback;
    MessageCallback _message_callback;
    CloseCallback _closed_callback;
    AnyEventCallback _anyevent_callback;

    // 组件内设置的连接关闭回调函数
    CloseCallback _server_closed_callback;

private:
    // 连接获取之后，所处的状态下，进行各种设置（给channel设置时间回调，启动读监控）
    void EstablishedInLoop()
    {
        // 1.修改连接状态
        assert(_status == CONNECTING);
        _status = CONNECTED; // 修改成以完成连接状态
        // 2. 启动读事件
        _channel.EnableRead();
        // 3. 调用回调函数
        if (_connection_callback)
            _connection_callback(shared_from_this());
    }
    // 实际的释放接口
    void ReleaseInLoop()
    {
        // 1. 修改连接状态
        _status = DISCONNECTING;
        // 2. 移除事件监控
        _channel.Remove();
        // 3. 关闭描述符
        _socket.Close();
        // 4. 如果当前定时器队列中还有定时销毁任务，则取消任务
        if (_loop->HasTimer(_conn_id))
            CancelInactiveReleaseInLoop();
        // 5. 调用关闭回调函数
        // 先调用用户的回调函数
        if (_closed_callback)
            _closed_callback(shared_from_this());
        // 后移除服务器内部管理的连接信息
        if (_server_closed_callback)
            _server_closed_callback(shared_from_this());
    }
    // 这个并不是实际的发送接口，而是将数据放入缓冲区，启动可写事件监控
    void SendInLoop(char *data, size_t len)
    {
        if (_status == DISCONNECTED)
            return;
        _out_buffer.Write(data, len);
        _out_buffer.MoveWirtePffset(len);

        if (_channel.WriteAble() == false)
            _channel.EnableWrite();
    }
    // 这个接口并非实际释放连接操作，需要判断还有没有数据待处理，待发送
    void CloseConnectionInLoop()
    {
        _status = DISCONNECTING; // 设置连接为半关闭状态
        if (_in_buffer.ReadAbleSize() > 0 && _message_callback)
            _message_callback(shared_from_this(), &_in_buffer);

        // 要么就是写入数据的时候出错关闭，要么就是没有待发送的数据，直接关闭
        if (_out_buffer.ReadAbleSize() > 0)
        {
            if (_channel.WriteAble() == false)
                _channel.EnableWrite();
        }
        if (_out_buffer.ReadAbleSize() == 0)
            ReleaseInLoop();
    }
    // 非活跃连接超时释放规则
    void EnableInactiveReleaseInLoop(int sec)
    {
        // 1.设置判断标志
        _enable_inactive_release = true;
        // 2.添加定时销毁任务
        // 如果存在就刷新一下定时任务即可
        if (_loop->HasTimer(_conn_id))
            _loop->TimerRefresh(_conn_id);
        // 不存在,则添加定时销毁任务，也就是添加ReleaseInLoop任务
        _loop->TimerAdd(_conn_id, sec, std::bind(&Connection::ReleaseInLoop, this));
    }
    // 取消非活跃销毁
    void CancelInactiveReleaseInLoop()
    {
        _enable_inactive_release = false;
        if (_loop->HasTimer(_conn_id))
            _loop->TimerCancel(_conn_id);
    }
    // 协议切换, 改变上下文，改变处理方法，也就是切换了协议
    void UpgradeInLoop(const Any &context, const ConnectionCallback &conn, const MessageCallback &msg,
                       const CloseCallback &closed, const AnyEventCallback &event)
    {
        SetContext(context);
        _connection_callback = conn;
        _message_callback = msg;
        _closed_callback = closed;
        _anyevent_callback = event;
    }

    /*五个事件回调函数*/
    // 描述符触发可读事件后调用的函数，接收socket数据放到接收缓冲区，然后调用_message_callback
    void HandleRead()
    {
        // 1. 接收Socket的数据，放到缓冲区
        char buf[65535];
        ssize_t ret = _socket.NonBlockRecv(buf, 65535);
        if (ret < 0) // 出错了
            return CloseConnectionInLoop();
        else if (ret == 0) // 没有读取到数据
            return;
        _in_buffer.Write(buf, ret);
        _in_buffer.MoveWirtePffset(ret);
        // 2. 调用message_callback进行业务处理
        if (_in_buffer.ReadAbleSize() > 0)
            return _message_callback(shared_from_this(), &_in_buffer);
    }
    // 描述符触发可写事件后调用的函数，将发送缓冲区的数据进行发送
    void HandleWrite()
    {
        ssize_t ret = _socket.NonBlockSend(_out_buffer.ReadPosition(), _out_buffer.ReadAbleSize());
        if (ret < 0)
        {
            // 发送错误，就该关闭连接了
            //  如果还有数据没处理，就先处理
            if (_in_buffer.ReadAbleSize() > 0)
                _message_callback(shared_from_this(), &_in_buffer);
            return ReleaseInLoop(); // 关闭释放操作
        }
        _out_buffer.MoveReadOffset(ret); // 读偏移向后移动
        // 没有数据待发送了，就把写事件监控关闭，否则，发送缓冲区中有空间则会一直有事件就绪，但是没有可发送的内容
        if (_out_buffer.ReadAbleSize() == 0)
            _channel.DisableWrite(); // 关闭写事件
        // 如果当前是连接待关闭状态，则有数据，发送完数据释放连接，没有数据则直接释放
        if (_status == DISCONNECTING && _out_buffer.ReadAbleSize() == 0)
        {
            return ReleaseInLoop();
        }
    }
    // 描述符触发挂断事件
    void HandleClose()
    {
        // 一旦连接挂断了，就什么都干不了了，因此只能做的是有数据待处理就处理一下，然后关闭连接
        if (_in_buffer.ReadAbleSize() > 0)
            _message_callback(shared_from_this(), &_in_buffer);
    }
    // 描述符触发出错事件
    void HandleError()
    {
        HandleClose();
    }
    // 描述符触发任意事件
    void HandleEvent()
    {
        // 1.刷新连接的活跃度--延迟定时任务的销毁任务
        // 2.调用组件使用者的任意事件回调函数
        // 是否启动了非活跃连接销毁
        if (_enable_inactive_release == true)
            _loop->TimerRefresh(_conn_id);
        if (_anyevent_callback)
            _anyevent_callback(shared_from_this());
    }

public:
    Connection(EventLoop *loop, uint64_t conn_id, int sockfd)
        : _conn_id(conn_id), _sockfd(sockfd), _enable_inactive_release(false), _loop(loop), _status(CONNECTING), _socket(_sockfd), _channel(sockfd, loop)
    {
        _channel.SetCloseCallBack(std::bind(&Connection::HandleClose, this));
        _channel.SetEventCallBack(std::bind(&Connection::HandleEvent, this));
        _channel.SetReadCallBack(std::bind(&Connection::HandleRead, this));
        _channel.SetWriteCallBack(std::bind(&Connection::HandleWrite, this));
        _channel.SetErrorCallBack(std::bind(&Connection::HandleError, this));
    }
    ~Connection() { DBG_LOG("release connetion %p", this); }
    // 发送数据，将数据放入到发送缓冲区，启动写事件监控
    void Send(char *data, size_t len)
    {
        _loop->RunInLoop(std::bind(&Connection::SendInLoop, this, data, len));
    }
    // 提供给组件使用者关闭连接的接口-并不实际关闭连接，而是判断有没有数据待处理
    void CloseConnection()
    {
        _loop->RunInLoop(std::bind(&Connection::CloseConnectionInLoop, this));
    }
    // 启动非活跃连接销毁-并定义超时事件
    void EnableInactiveRelease(int sec)
    {
        _loop->RunInLoop(std::bind(&Connection::EnableInactiveReleaseInLoop, this, sec));
    }
    // 关闭非活跃连接销毁
    void CancelInactiveRelease()
    {
        _loop->RunInLoop(std::bind(&Connection::CancelInactiveReleaseInLoop, this));
    }
    // 协议切换-重置上下文以及阶段性处理函数 -- 非线程安全的
    void Upgrade(const Any &context, const ConnectionCallback &conn, const MessageCallback &msg,
                 const CloseCallback &closed, const AnyEventCallback &event)
    {
        //防备新的事件触发后，处理的时候，切换任务还没有被执行--会导致数据使用原来的协议处理了
        _loop->AssertInLoop();
        _loop->RunInLoop(std::bind(&Connection::UpgradeInLoop, this, context, conn, msg, closed, event));
    }

    // 获取文件描述符
    int Fd() { return _sockfd; }
    // 获取连接ID
    uint64_t ConnectionId() { return _conn_id; }
    // 是否处于一个CONNECTED状态
    bool Connected() { return _status == CONNECTED; }
    // 设置上下文
    void SetContext(const Any &context) { _context = context; }
    // 获取上下文
    Any *GetContext() { return &_context; }

    // 设置回调函数
    void SetConnectionCallback(const ConnectionCallback &cb) { _connection_callback = cb; }
    void SetMessageCallback(const MessageCallback &cb) { _message_callback = cb; }
    void SetCloseCallback(const CloseCallback &cb) { _closed_callback = cb; }
    void SetAnyEventCallback(const AnyEventCallback &cb) { _anyevent_callback = cb; }
    void SetSvrCloseCallback(const CloseCallback &cb) { _server_closed_callback = cb; }

    // 连接建立就绪后，进行channel回调设置，启动读监控，调用_connected_callback
    void Established()
    {
        _loop->RunInLoop(std::bind(&Connection::EstablishedInLoop, this));
    }
};